package com.clp.protocol.iec104.definition;

import com.clp.protocol.core.utils.EnumElemDoesNotExistException;
import com.clp.protocol.iec104.apdu.Apdu;
import com.clp.protocol.iec104.apdu.IApdu;
import com.clp.protocol.iec104.apdu.SApdu;
import com.clp.protocol.iec104.apdu.UApdu;
import com.clp.protocol.iec104.apdu.apci.CtrlArea;
import com.clp.protocol.iec104.apdu.apci.ICtrlArea;
import com.clp.protocol.iec104.apdu.apci.SCtrlArea;
import com.clp.protocol.iec104.apdu.apci.UCtrlArea;
import lombok.AllArgsConstructor;
import lombok.Getter;

/**
 * Apdu类型：I帧、S帧、U帧格式的定义，用一个字节类型表示控制域的第一个字节，该字节用来区分帧的类型
 */
@Getter
@AllArgsConstructor
public enum ApduType {
    /**
     * S帧
     */
    SType((byte) 0x01, (byte) 0x03, SApdu.class, SCtrlArea.class, "S帧"){
        @Override
        public CtrlArea<?> newInvalidCtrlArea() {
            return new SCtrlArea();
        }

        @Override
        public Apdu newInvalidApdu() {
            return new SApdu();
        }
    },
    /**
     * U帧
     */
    UType((byte) 0x03, (byte) 0x03, UApdu.class, UCtrlArea.class, "U帧") {
        @Override
        public CtrlArea<?> newInvalidCtrlArea() {
            return new UCtrlArea();
        }

        @Override
        public Apdu newInvalidApdu() {
            return new UApdu();
        }
    },
    /**
     * I帧
     */
    IType((byte) 0x00, (byte) 0x01, IApdu.class, ICtrlArea.class, "I帧") {
        @Override
        public CtrlArea<?> newInvalidCtrlArea() {
            return new ICtrlArea();
        }

        @Override
        public Apdu newInvalidApdu() {
            return new IApdu();
        }
    };

    /**
     * 帧类型的定义部分
     */
    private final byte typeDef;
    /**
     * 帧类型的有效位掩码
     */
    private final byte typeDefMask;
    /**
     * 对应的Apdu类
     */
    private final Class<? extends Apdu> apduClass;
    /**
     * 对应的控制域类
     */
    private final Class<? extends CtrlArea<?>> ctrlAreaClass;
    /**
     * 描述
     */
    private final String desc;

    public abstract CtrlArea<?> newInvalidCtrlArea();

    public abstract Apdu newInvalidApdu();

    /**
     * 根据控制域返回FrameType类型
     *
     * @param ctrlAreaBytes 控制域字节数组
     * @return
     */
    public static ApduType gain(byte[] ctrlAreaBytes) {
        byte one = ctrlAreaBytes[0];
        if ((one & IType.typeDefMask) == IType.typeDef) {
            return IType;
        }
        if ((one & SType.typeDefMask) == SType.typeDef) {
            return SType;
        }
        if ((one & UType.typeDefMask) == UType.typeDef) {
            return UType;
        }
        throw new EnumElemDoesNotExistException(ApduType.class);
    }
}
